package core;

import java.io.*;
import java.util.*;

import javax.swing.*;

import wa.*;

public class SongIndex extends Index {
	
//	public static final String INDEX_FILE = "data/songs.dat",
//									DATA_DIR = "data/songs/";
	
	private static final long serialVersionUID = 7915970580217795806L;
	
	private Map<Integer, SongRecord> records;
	private List<Integer> tableModel;
	private File dataDir;
	
	public SongIndex() {
		super(Preferences.SONG_INDEX_FILE);
		dataDir = Preferences.SONG_DIR;
		dataDir.mkdirs();
		tableModel = new ArrayList<Integer>();
		records = new HashMap<Integer, SongRecord>();
		setDisplayCols(SongRecord.NUM_FIELDS);
	}
	
	public void add(SongRecord sr) {
		addToIndex(sr);
		fireTableRowsInserted(records.size()-1, records.size()-1);
		saveWithoutUpdate();
	}
	private void addToIndex(SongRecord sr) {
		synchronized(tableModel) {
			tableModel.add(sr.getId());
			records.put(sr.getId(), sr);
		}
	}
	public SongRecord get(Integer id) {
		return records.get(id);
	}
	public SongRecord getByIndex(int i) {
		return get(tableModel.get(i));
	}
	public void remove(Integer id) {
		synchronized(records){
			if (get(id).delete()) {
				records.remove(id);
				
				int index = tableModel.indexOf(id);
				if (index != -1) {
					tableModel.remove(index);
					fireTableRowsDeleted(index, index);
				}
				saveWithoutUpdate();
			}
		}
	}
	public void removeByIndex(int i) {
		remove(tableModel.get(i));
	}
	public SongRecord newRecord(String title) {
		SongRecord sr = new SongRecord(nextId(), title, Preferences.SONG_DIR.getPath());
		return sr;
	}
	
	/*public void save() {
		saveWithoutUpdate();
		fireTableRowsInserted(0, records.size()-1);
	}
	private void saveWithoutUpdate() {
		try {
			ObjectOutputStream oos = new ObjectOutputStream(
					new FileOutputStream(indexFile));
			oos.writeObject(records);
			oos.writeObject(nextId);
			oos.close();
			
		} catch(IOException ex) {
			ex.printStackTrace();
		}
	}
	
	@SuppressWarnings("unchecked")
	public static SongIndex load(File f) {
		if(!f.exists())
			return null;
		
		SongIndex ind = new SongIndex();
		try {
			ObjectInputStream ois = new ObjectInputStream(
					new FileInputStream(f));
			ind.records = (ArrayList<SongRecord>)ois.readObject();
			ind.nextId = (Integer)ois.readObject();
			ois.close();
			
		} catch(IOException ex) {
			ex.printStackTrace();
			return null;
		} catch(ClassNotFoundException ex) {
			ex.printStackTrace();
			return null;
		}
		
		return ind;
	}*/
	
	public void save() {
		saveWithoutUpdate();
//		fireTableRowsInserted(0, records.size()-1);
		fireTableDataChanged();
	}
	private void saveWithoutUpdate() {
		super.save();
	}
	
	// Serialization methods
	protected void writeObject(ObjectOutputStream out) throws IOException {
		super.writeObject(out);
		out.writeObject(records);
//		out.writeObject(tableModel);
	}
	@SuppressWarnings("unchecked")
	protected void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		super.readObject(in);
		this.records = (Map<Integer, SongRecord>)in.readObject();
//		this.tableModel = (List<Integer>)in.readObject();
		tableModel.addAll(records.keySet());
	}
	public static SongIndex load(File file) {
		if(!file.exists())
			return null;
		
		SongIndex index = new SongIndex();
		Index.load(index, file);
		return index;
	}
	
	
	// TableModel
	public int getRowCount() {
		return tableModel.size();
	}
	public String getColumnName(int column) {
		return SongRecord.fieldNames[column];
	}
	public Class<?> getColumnClass(int columnIndex) {
		return String.class;
	}
	public Object getValueAt(int rowIndex, int columnIndex) {
		return getByIndex(rowIndex).getField(columnIndex);
	}
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		getByIndex(rowIndex).setField(columnIndex, aValue);
	}
	
	
	public void importFolder(File inDir) {
		if (inDir.isDirectory()) {
			for(File f : inDir.listFiles(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					return name.toLowerCase().endsWith(".txt");
				}
			}))
				if (f.isFile()) {
					SongRecord sr  = new SongRecord(nextId(), f);
					addToIndex(sr);
					System.out.println(sr);
				}
		save();
		}
	}
	
	public void importWADatabase(File inDir) {
		
		try {
			RandomAccessFile indexFile = new RandomAccessFile(inDir.getPath() + 
					"/" + WADataParser.INDEX_FILE, "r");
			RandomAccessFile lyricsFile = new RandomAccessFile(inDir.getPath() + 
					"/" + WADataParser.LYRICS_FILE, "r");
			
			WAFieldDescriptor[] fds = WADataParser.readFieldDescriptors(indexFile);
			WADataItem[] dataItems = WADataParser.readDataItems(indexFile, fds);
			
			lyricsFile.seek(WADataParser.LYRICS_BLOCK_LEN);	// skip past header (512 byte block)
			
			for(int i=0; i<dataItems.length; i++) {		// for each song in index
				
				Object lyrics2Field = dataItems[i].fields[31];	// get LYRICS2 field
				if (lyrics2Field == null)	// if lyrics don't exist
					continue;
				
				int lyricsNo = ((Integer)lyrics2Field).intValue();
				StringBuilder sb = new StringBuilder();
				
				// read lyrics
				WALyricsBlock wlb = null;			// keep reading blocks until
				do {								// lyrics number matches or exceeds target
					wlb = WADataParser.readLyricsBlock(lyricsFile);
					if (wlb == null)
						break;
					else if (wlb.id == lyricsNo)
						sb.append(wlb.text);
					
				} while (wlb.id <= lyricsNo);
				
				// create a song record; add it to the song index file
				if (sb.length() > 0) {
					SongRecord sr = new SongRecord(nextId(), (String)dataItems[i].fields[2], dataDir.toString());
					sr.setField(SongRecord.AUTHOR, (String)dataItems[i].fields[3]);
					sr.setField(SongRecord.COPYRIGHT, (String)dataItems[i].fields[4]);
					sr.setField(SongRecord.KEY, (String)dataItems[i].fields[6]);
					sr.setField(SongRecord.SLIDE_ORDER, (String)dataItems[i].fields[24]);
					sr.setLyrics(sb.toString().trim());
					System.out.println("creating record: " + sr);
					
					addToIndex(sr);
				}
			}
		}
		catch (FileNotFoundException ex) {
			ex.printStackTrace();
		}
		catch (IOException ex) {
			ex.printStackTrace();
		}
		
		save();
	}
	
	// Test stub
	public static void main (String[] args) {
		SwingUtilities.invokeLater(new Thread() {
			@Override
			public void run() {
				SongIndex sm = new SongIndex();
				sm.importWADatabase(new File("data/wa/"));
//				sm.save();
				
//				SongIndex sm = SongIndex.load(new File("data/songs.dat"));
				
				JFrame fr = new JFrame();
				JTable table = new JTable(sm);
				table.setAutoCreateRowSorter(true);
				JScrollPane scrollPane = new JScrollPane(table);
				table.setFillsViewportHeight(true);
				fr.add(scrollPane);
				fr.pack();
				fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				fr.setVisible(true);
			}
		});
	}
}
